<template>
  <el-dialog
    v-model="dialogVisible"
    title="图片裁剪"
    width="800px"
    center
    :close-on-click-modal="false"
    @close="handleClose"
  >
    <div class="crop-dialog-content">
      <!-- 裁剪区域 -->
      <div class="crop-section">
        <div class="crop-container">
          <img
            ref="imageRef"
            :src="imageSrc"
            style="display: block; max-width: 100%; height: 100%"
            alt="裁剪图片"
          />
        </div>

        <!-- 预览区域 -->
        <div class="preview-section">
          <h4>预览效果</h4>
          <div class="preview-container">
            <div class="preview-box" :style="previewStyle">
              <img v-if="previewImg" :src="previewImg" alt="预览图片" />
            </div>
          </div>
        </div>
      </div>

      <!-- 操作控制区域 -->
      <div class="control-section">
        <div class="control-group">
          <h4>裁剪控制</h4>
          <div class="control-buttons">
            <el-button-group>
              <el-button size="small" :icon="RefreshLeft" @click="rotateLeft">
                左旋转
              </el-button>
              <el-button size="small" :icon="RefreshRight" @click="rotateRight">
                右旋转
              </el-button>
            </el-button-group>

            <el-button-group>
              <el-button size="small" :icon="Switch" @click="scaleX">
                水平翻转
              </el-button>
              <el-button size="small" :icon="Sort" @click="scaleY">
                垂直翻转
              </el-button>
            </el-button-group>

            <el-button size="small" :icon="RefreshRight" @click="reset">
              重置
            </el-button>
          </div>
        </div>

        <div class="control-group">
          <h4>缩放控制</h4>
          <div class="scale-controls">
            <el-button size="small" :icon="ZoomIn" @click="zoomIn">
              放大
            </el-button>
            <el-button size="small" :icon="ZoomOut" @click="zoomOut">
              缩小
            </el-button>
            <el-button size="small" :icon="FullScreen" @click="resetScale">
              适应
            </el-button>
          </div>
        </div>

        <div class="control-group">
          <h4>裁剪比例</h4>
          <el-radio-group v-model="aspectRatio" @change="changeAspectRatio">
            <el-radio :label="0">自由比例</el-radio>
            <el-radio :label="16 / 9">16:9</el-radio>
            <el-radio :label="4 / 3">4:3</el-radio>
            <el-radio :label="1">1:1</el-radio>
          </el-radio-group>
        </div>
      </div>
    </div>

    <template #footer>
      <div class="dialog-footer">
        <el-button @click="handleClose">取消</el-button>
        <el-button type="primary" :loading="processing" @click="handleConfirm">
          确认裁剪
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import {
  ref,
  computed,
  watch,
  nextTick,
  onMounted,
  onBeforeUnmount
} from "vue";
import { ElMessage } from "element-plus";
import {
  RefreshLeft,
  RefreshRight,
  Switch,
  Sort,
  ZoomIn,
  ZoomOut,
  FullScreen
} from "@element-plus/icons-vue";
import Cropper from "cropperjs";
import "cropperjs/dist/cropper.css";

interface Props {
  visible: boolean;
  imageSrc?: string;
}

interface Emits {
  (e: "update:visible", value: boolean): void;
  (e: "confirm", croppedFile: File): void;
}

const props = withDefaults(defineProps<Props>(), {
  imageSrc: ""
});

const emit = defineEmits<Emits>();

// 对话框显示状态
const dialogVisible = computed({
  get: () => props.visible,
  set: value => emit("update:visible", value)
});

// 组件引用
const imageRef = ref<HTMLImageElement>();
let cropper: Cropper | null = null;

// 状态管理
const processing = ref(false);
const aspectRatio = ref(0); // 0表示自由比例
const previewImg = ref("");
const previewStyle = ref({});
const scaleXVal = ref(1);
const scaleYVal = ref(1);

// 监听对话框显示状态
watch(dialogVisible, async visible => {
  if (visible && props.imageSrc) {
    await nextTick();
    initCropper();
    // 重置状态
    aspectRatio.value = 0;
    scaleXVal.value = 1;
    scaleYVal.value = 1;
  } else {
    destroyCropper();
  }
});

// 初始化裁剪器
const initCropper = () => {
  if (imageRef.value && !cropper) {
    cropper = new Cropper(imageRef.value, {
      aspectRatio: NaN,
      viewMode: 1,
      dragMode: "move",
      autoCropArea: 0.8,
      restore: false,
      guides: true,
      center: true,
      highlight: true,
      cropBoxMovable: true,
      cropBoxResizable: true,
      toggleDragModeOnDblclick: false,
      crop: handleCropChange
    });
  }
};

// 销毁裁剪器
const destroyCropper = () => {
  if (cropper) {
    cropper.destroy();
    cropper = null;
  }
};

// 裁剪变化回调
const handleCropChange = (event: any) => {
  const canvas = cropper?.getCroppedCanvas({
    width: 200,
    height: 150
  });
  if (canvas) {
    previewImg.value = canvas.toDataURL();
    previewStyle.value = {
      width: "200px",
      height: "150px",
      overflow: "hidden",
      margin: "0 auto",
      border: "1px solid #ddd",
      borderRadius: "4px"
    };
  }
};

// 裁剪操作方法
const rotateLeft = () => {
  cropper?.rotate(-90);
};

const rotateRight = () => {
  cropper?.rotate(90);
};

const scaleX = () => {
  scaleXVal.value = scaleXVal.value === 1 ? -1 : 1;
  cropper?.scaleX(scaleXVal.value);
};

const scaleY = () => {
  scaleYVal.value = scaleYVal.value === 1 ? -1 : 1;
  cropper?.scaleY(scaleYVal.value);
};

const zoomIn = () => {
  cropper?.zoom(0.1);
};

const zoomOut = () => {
  cropper?.zoom(-0.1);
};

const resetScale = () => {
  cropper?.reset();
};

const reset = () => {
  aspectRatio.value = 0;
  scaleXVal.value = 1;
  scaleYVal.value = 1;
  cropper?.reset();
};

// 改变裁剪比例
const changeAspectRatio = (ratio: number) => {
  if (cropper) {
    cropper.setAspectRatio(ratio === 0 ? NaN : ratio);
  }
};

// 确认裁剪
const handleConfirm = () => {
  if (!cropper) {
    ElMessage.error("裁剪组件未初始化");
    return;
  }

  processing.value = true;

  try {
    // 获取裁剪后的canvas
    const canvas = cropper.getCroppedCanvas({
      width: 800, // 输出宽度
      minWidth: 200,
      minHeight: 200,
      maxWidth: 1200,
      maxHeight: 1200,
      fillColor: "#fff",
      imageSmoothingEnabled: true,
      imageSmoothingQuality: "high"
    });

    // 将canvas转换为blob
    canvas.toBlob(
      (blob: Blob | null) => {
        if (blob) {
          // 创建File对象
          const file = new File([blob], "cropped-image.jpg", {
            type: "image/jpeg",
            lastModified: Date.now()
          });

          emit("confirm", file);
          handleClose();
        } else {
          ElMessage.error("图片裁剪失败，请重试");
        }
        processing.value = false;
      },
      "image/jpeg",
      0.9
    );
  } catch (error) {
    console.error("裁剪失败:", error);
    ElMessage.error("图片裁剪失败，请重试");
    processing.value = false;
  }
};

// 关闭对话框
const handleClose = () => {
  // 销毁裁剪器
  destroyCropper();

  // 清理预览图片
  if (previewImg.value && previewImg.value.startsWith("blob:")) {
    URL.revokeObjectURL(previewImg.value);
  }

  // 重置状态
  previewImg.value = "";
  previewStyle.value = {};
  processing.value = false;

  emit("update:visible", false);
};

// 组件卸载时清理
onBeforeUnmount(() => {
  destroyCropper();
});
</script>

<style scoped lang="scss">
// 响应式设计
@media (width <= 768px) {
  .crop-dialog-content {
    .crop-section {
      flex-direction: column;

      .preview-section {
        width: 100%;
      }
    }

    .control-section {
      .control-buttons {
        flex-wrap: wrap;
      }
    }
  }
}

.crop-dialog-content {
  padding: 20px;

  .crop-section {
    display: flex;
    gap: 20px;
    margin-bottom: 24px;

    .crop-container {
      flex: 1;
      height: 400px;
      overflow: hidden;
      border: 2px dashed var(--el-border-color);
      border-radius: 8px;

      :deep(.vue-cropper) {
        width: 100%;
        height: 100%;
      }
    }

    .preview-section {
      width: 200px;
      text-align: center;

      h4 {
        margin: 0 0 12px;
        font-size: 16px;
        font-weight: 600;
        color: #1f2937;
      }

      .preview-container {
        .preview-box {
          display: flex;
          align-items: center;
          justify-content: center;
          min-height: 100px;
          background: #f5f5f5;
          border: 1px solid #ddd;
          border-radius: 4px;

          img {
            display: block;
            max-width: 100%;
            max-height: 100%;
          }
        }
      }
    }
  }

  .control-section {
    .control-group {
      margin-bottom: 20px;

      h4 {
        margin: 0 0 12px;
        font-size: 14px;
        font-weight: 600;
        color: #1f2937;
      }

      .control-buttons {
        display: flex;
        gap: 12px;
        align-items: center;

        :deep(.el-button-group) {
          .el-button {
            padding: 4px 12px;
          }
        }
      }

      .scale-controls {
        display: flex;
        gap: 8px;

        .el-button {
          padding: 4px 12px;
        }
      }

      :deep(.el-radio-group) {
        .el-radio {
          margin-right: 16px;
        }
      }
    }
  }
}

.dialog-footer {
  display: flex;
  gap: 12px;
  justify-content: flex-end;
}
</style>
